﻿using CLM.Gestao.Administrador.DAL;
using CLM.Gestao.Importacao;
using CLM.Gestao.Interfaces;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace CLM.Gestao.Administrador.BLL
{
    public class Produto : ProdutoBLO<TB_PRODUTO>
    {
        #region Propriedades

        public int IdProduto { get; set; }
        public string CodigoProduto { get; set; }
        public string NomeProduto { get; set; }
        public bool? IndicaAtivo { get; set; }
        public int? IdProdutoGlobal { get; set; }
        public string NomeProdutoGlobal { get; set; }
        public int? IdProdutoPai { get; set; }
        public string NomeProdutoPai { get; set; }
        public int? IdCentroCusto { get; set; }
        public string NomeCentroCusto { get; set; }
        public string CodigoProdutoSemiAcabado { get; set; }
        public int? IdProdutoTipo { get; set; }
        public string NomeProdutoTipo { get; set; }
        public int? IdProdutoFamilia { get; set; }
        public string NomeProdutoFamilia { get; set; }
        public int? IdUnidadeNegocio { get; set; }
        public string NomeUnidadeNegocio { get; set; }

        #endregion Propriedades

        #region Conversões

        private List<TB_PRODUTO> ConvertToEDM(List<Lista> pLista)
        {
            List<TB_PRODUTO> List = (from l in pLista
                                     select new TB_PRODUTO
                                     {
                                         ID_PRODUTO = l.IdProduto,
                                         CODIGO_PRODUTO = l.CodigoProduto.Trim(),
                                         NOME_PRODUTO = l.NomeProduto.Trim(),
                                         INDICA_ATIVO = l.IndicaAtivo,
                                         ID_PRODUTO_GLOBAL = l.IdProdutoGlobal,
                                         ID_PRODUTO_PAI = l.IdProdutoPai,
                                         ID_CENTRO_CUSTO = l.IdCentroCusto,
                                         CODIGO_PRODUTO_SEMI_ACABADO = l.CodigoProdutoSemiAcabado.Trim(),
                                         ID_PRODUTO_TIPO = l.IdProdutoTipo,
                                         ID_PRODUTO_FAMILIA = l.IdProdutoFamilia,
                                         ID_UNIDADE_NEGOCIO = l.IdUnidadeNegocio
                                     }).ToList();
            return List;
        }

        private List<Lista> ConvertToContext(IQueryable<TB_PRODUTO> pContext)
        {
            List<Lista> List = (from l in pContext
                                select new Lista
                                {
                                    IdProduto = l.ID_PRODUTO,
                                    CodigoProduto = l.CODIGO_PRODUTO.Trim(),
                                    NomeProduto = l.NOME_PRODUTO.Trim(),
                                    IndicaAtivo = l.INDICA_ATIVO,
                                    IdProdutoGlobal = l.ID_PRODUTO_GLOBAL,
                                    CodigoProdutoGlobal = l.TB_PRODUTO_GLOBAL.CODIGO_PRODUTO_GLOBAL.Trim(),
                                    NomeProdutoGlobal = l.TB_PRODUTO_GLOBAL.NOME_PRODUTO_GLOBAL.Trim(),
                                    IdProdutoPai = l.ID_PRODUTO_PAI,
                                    NomeProdutoPai = l.TB_PRODUTO2.NOME_PRODUTO.Trim(),
                                    IdCentroCusto = l.ID_CENTRO_CUSTO,
                                    NomeCentroCusto = l.TB_CENTRO_CUSTO.NOME_CENTRO_CUSTO.Trim(),
                                    CodigoProdutoSemiAcabado = l.CODIGO_PRODUTO_SEMI_ACABADO.Trim(),
                                    IdProdutoTipo = l.ID_PRODUTO_TIPO,
                                    NomeProdutoTipo = l.TB_PRODUTO_TIPO.NOME_PRODUTO_TIPO.Trim(),
                                    IdProdutoFamilia = l.ID_PRODUTO_FAMILIA,
                                    NomeProdutoFamilia = l.TB_PRODUTO_FAMILIA.NOME_PRODUTO_FAMILIA.Trim(),
                                    IdUnidadeNegocio = l.ID_UNIDADE_NEGOCIO,
                                    NomeUnidadeNegocio = l.TB_UNIDADE_NEGOCIO.NOME_UNIDADE_NEGOCIO.Trim()
                                }).ToList();
            return List;
        }

        #endregion Conversões

        #region CRUD
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pLista"></param>
        public void Add(List<Lista> pLista)
        {
            try
            {
                foreach (var item in ConvertToEDM(pLista))
                    base.Add(item);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pLista"></param>
        public void Delete(List<Lista> pLista)
        {
            try
            {
                foreach (var item in ConvertToEDM(pLista))
                    base.Delete(item);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pLista"></param>
        public void Update(List<Lista> pLista)
        {
            try
            {
                foreach (var item in ConvertToEDM(pLista))
                    base.Update(item);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Efetua a pesquisa na tabela, filtrando as solicitações do usuário
        /// </summary>
        /// <param name="pPesquisa">pPesquisa</param>
        /// <returns>Lista</returns>
        private IQueryable<TB_PRODUTO> Get(Lista pPesquisa)
        {
            IQueryable<TB_PRODUTO> Consulta;

            Consulta = from p in GetAll()
                       select p;
            if (pPesquisa != null)
            {
                if (!string.IsNullOrWhiteSpace(pPesquisa.CodigoProduto))
                    Consulta = from p in Consulta where p.CODIGO_PRODUTO.Contains(pPesquisa.CodigoProduto) select p;

                if (!string.IsNullOrWhiteSpace(pPesquisa.NomeProduto))
                    Consulta = from p in Consulta where p.NOME_PRODUTO.Contains(pPesquisa.NomeProduto) select p;

                if (pPesquisa.IdProdutoTipo > 0)
                    Consulta = from p in Consulta where p.ID_PRODUTO_TIPO == pPesquisa.IdProdutoTipo select p;

                if (pPesquisa.IdProdutoPai > 0)
                    Consulta = from p in Consulta where p.ID_PRODUTO_PAI == pPesquisa.IdProdutoPai select p;

                if (pPesquisa.IdProdutoGlobal > 0)
                    Consulta = from p in Consulta where p.ID_PRODUTO_GLOBAL == pPesquisa.IdProdutoGlobal select p;

                if (pPesquisa.IdProdutoFamilia > 0)
                    Consulta = from p in Consulta where p.ID_PRODUTO_FAMILIA == pPesquisa.IdProdutoFamilia select p;

                if (pPesquisa.IdUnidadeNegocio > 0)
                    Consulta = from p in Consulta where p.ID_UNIDADE_NEGOCIO == pPesquisa.IdUnidadeNegocio select p;

                // if (pPesquisa.IdPeriodo > 0)
                //    Consulta = from p in Consulta.SelectMany(s => s.TB_PRODUTO_DRIVER_RATEIO_VALOR.Where(wr => wr.ID_PERIODO == pPesquisa.IdPeriodo)) select p.TB_PRODUTO;

            }
            return Consulta;
        }

        #endregion CRUD

        #region Retorna Listas e Itens

        public List<Lista> GetLista()
        {
            return GetLista(new Lista());
        }

        public List<Lista> GetLista(Lista pPesquisa)
        {
            var ListaProduto = ConvertToContext(Get(pPesquisa));

            if (pPesquisa != null && pPesquisa.IdPeriodo != null)
            {
                foreach (var item in ListaProduto)
                    Produto.GetDrivers(item, (int)pPesquisa.IdPeriodo);
            }
            return ListaProduto;
        }

        public List<Itens> GetItens()
        {
            return GetItens(new Lista());
        }

        public List<Itens> GetItens(Lista pPesquisa)
        {
            List<Itens> ListaProduto = (from p in Get(pPesquisa)
                                        select new Itens()
                                        {
                                            CodigoProduto = p.CODIGO_PRODUTO.Trim(),
                                            IdProduto = p.ID_PRODUTO,
                                            NomeProduto = p.NOME_PRODUTO.Trim()
                                        }).ToList();
            return ListaProduto;
        }

        public List<Lista> GetDivergenciasProdutos()
        {
            return GetDivergenciasProdutos(new Lista());
        }

        public List<Lista> GetDivergenciasProdutos(Lista pPesquisa)
        {
            List<Lista> ListaDivergenciaProduto = (from p in Get(pPesquisa)
                                                   select new Lista()
                                        {
                                            CodigoProduto = p.CODIGO_PRODUTO,
                                            CodigoProdutoGlobal = p.TB_PRODUTO_GLOBAL.CODIGO_PRODUTO_GLOBAL,
                                            NomeProduto = p.NOME_PRODUTO,
                                            NomeProdutoGlobal = p.TB_PRODUTO_GLOBAL.NOME_PRODUTO_GLOBAL
                                        }).ToList();

            BLL.ProdutoGlobal Global = new ProdutoGlobal();
            List<Lista> GlobalSemNacional = (from p in Global.GetLista()
                                             where p.IdProduto == 0
                                             select new Lista()
                                             {
                                                 CodigoProduto = "",
                                                 CodigoProdutoGlobal = p.CodigoProdutoGlobal,
                                                 NomeProduto = "",
                                                 NomeProdutoGlobal = p.NomeProdutoGlobal
                                             }).ToList();

            return ListaDivergenciaProduto.Union(GlobalSemNacional).ToList();
            //return ListaDivergenciaProduto.ToList();
        }

        #endregion Retorna Listas e Itens

        #region Consultas


        #endregion Consultas

        #region Processos

        #region Importar Ordem Produto

        public void ImportaOrdemProdutosGlobais(string pFileName)
        {
            ExcelConnection = new Importacao.Excel();
            dsProdutos = null;

            ValidaLayoutImportacaoOrdem(pFileName);
            ValidaDadosImportacaoOrdem();

            AtualizaOrdemProduto();
        }

        private void ValidaLayoutImportacaoOrdem(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsProdutos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsProdutos != null && dsProdutos.Tables != null && dsProdutos.Tables.Count > 0 && dsProdutos.Tables[0].Rows.Count > 0)
            {
                try { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("Codigo Hyperion"); }
                catch { throw new Exception("A coluna (\"Codigo Hyperion\") não foi encontrada no arquivo."); }

                try { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("Descrição Hyperion"); }
                catch { throw new Exception("A coluna (\"Descrição Hyperion\") não foi encontrada no arquivo."); }
            }
        }

        private void ValidaDadosImportacaoOrdem()
        {
            if (dsProdutos != null && dsProdutos.Tables != null && dsProdutos.Tables.Count > 0 && dsProdutos.Tables[0].Rows.Count > 0)
            {
                var ProdutoGlobal = (from p in dsProdutos.Tables[0].AsEnumerable()
                                     where !string.IsNullOrWhiteSpace(p.Field<string>("Codigo Hyperion")) && string.IsNullOrWhiteSpace(p.Field<string>("Descrição Hyperion"))
                                     select p).ToList();

                if (ProdutoGlobal != null && ProdutoGlobal.Count() > 0)
                    throw new Exception("Existem nomes de produtos globais em branco.\nPor favor, reveja a planilha e reinicie a importação.");
            }
        }

        private void AtualizaOrdemProduto()
        {
            ProdutoGlobal Global = new ProdutoGlobal();
            OnImportData(this, new ImportDataEventArgs("Importando ordem de Produtos Globais..."));

            // Colunas A, D
            int Ord = 0;
            var ProdutosExcel = (from p in dsProdutos.Tables[0].AsEnumerable()
                                 group p by new
                                 {
                                     CodigoProdutoGlobal = p.Field<string>("Codigo Hyperion").Trim().PadLeft(6, '0'),
                                     NomeProdutoGlobal = p.Field<string>("Descrição Hyperion").Trim()
                                 } into gr
                                 select new ProdutoGlobal.Lista
                                 {
                                     CodigoProdutoGlobal = gr.Key.CodigoProdutoGlobal,
                                     NomeProdutoGlobal = gr.Key.NomeProdutoGlobal,
                                     OrdemExibicao = Ord++
                                 }).ToList();

            var ProdutosSQL = (from p in Global.GetLista()
                               select new ProdutoGlobal.Lista
                               {
                                   CodigoProdutoGlobal = p.CodigoProdutoGlobal,
                                   NomeProdutoGlobal = p.NomeProdutoGlobal,
                                   IdProdutoGlobal = p.IdProdutoGlobal
                               }).ToList();

            var Alterados = (from p in ProdutosExcel
                             join db in ProdutosSQL
                             on p.CodigoProdutoGlobal equals db.CodigoProdutoGlobal
                             select new ProdutoGlobal.Lista
                             {
                                 IdProdutoGlobal = db.IdProdutoGlobal,
                                 CodigoProdutoGlobal = p.CodigoProdutoGlobal,
                                 NomeProdutoGlobal = p.NomeProdutoGlobal,
                                 OrdemExibicao = p.OrdemExibicao
                             }).ToList();
            int i = 0;
            if (Alterados != null && Alterados.Count() > 0)
            {
                foreach (var item in Alterados)
                {
                    Global.Update(new TB_PRODUTO_GLOBAL()
                    {
                        ID_PRODUTO_GLOBAL = item.IdProdutoGlobal,
                        CODIGO_PRODUTO_GLOBAL = item.CodigoProdutoGlobal,
                        NOME_PRODUTO_GLOBAL = item.NomeProdutoGlobal,
                        ORDEM_EXIBICAO = item.OrdemExibicao,
                        INDICA_ATIVO = true
                    });
                    i++;
                    OnImportData(this, new ImportDataEventArgs("Atualizando ordem de Produtos Globais...", i, Alterados.Count()));
                }
            }
        }

        #endregion

        #region Importa Produtos Globais

        private DataSet dsProdutos;

        private Importacao.Excel ExcelConnection;

        public void ImportaProdutosGlobais(string pFileName)
        {
            ExcelConnection = new Importacao.Excel();
            dsProdutos = null;

            ValidaLayoutImportacao(pFileName);
            ValidaDadosImportacao();

            AtualizaUnidadeNegocio();
            AtualizaProdutoTipo();
            AtualizaProdutoFamilia();
            AtualizaProdutoGlobal();

            AtualizaRelacaoProdutoNacionalGlobal();
        }

        private void ValidaLayoutImportacao(string pFileName)
        {
            // Acessa o documento Excel e efetua a consulta na planilha "Dados"
            try { dsProdutos = ExcelConnection.ExecuteRecordset(pFileName, "SELECT * FROM [Dados$]"); }
            catch { throw new Exception("A planilha não possui a aba \"Dados\"."); }

            if (dsProdutos != null && dsProdutos.Tables != null && dsProdutos.Tables.Count > 0 && dsProdutos.Tables[0].Rows.Count > 0)
            {
                try
                { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("Codigo Protheus"); }
                catch { throw new Exception("A coluna (\"Codigo Protheus\") não foi encontrada no arquivo."); }

                try { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("Descrição Protheus"); }
                catch { throw new Exception("A coluna (\"Descrição Protheus\") não foi encontrada no arquivo."); }

                try { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("Codigo Hyperion"); }
                catch { throw new Exception("A coluna (\"Codigo Hyperion\") não foi encontrada no arquivo."); }

                try { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("Descrição Hyperion"); }
                catch { throw new Exception("A coluna (\"Descrição Hyperion\") não foi encontrada no arquivo."); }

                try { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("Familia Hyperion"); }
                catch { throw new Exception("A coluna (\"Familia Hyperion\") não foi encontrada no arquivo."); }

                try { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("Centro de Custos"); }
                catch { throw new Exception("A coluna (\"Centro de Custos\") não foi encontrada no arquivo."); }

                try { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("BU"); }
                catch { throw new Exception("A coluna (\"BU\") não foi encontrada no arquivo."); }

                try { var aux = dsProdutos.Tables[0].Rows[0].Field<object>("Tipo"); }
                catch { throw new Exception("A coluna (\"Tipo\") não foi encontrada no arquivo."); }
            }
        }

        private void ValidaDadosImportacao()
        {
            if (dsProdutos != null && dsProdutos.Tables != null && dsProdutos.Tables.Count > 0 && dsProdutos.Tables[0].Rows.Count > 0)
            {
                var ProdutoGlobal = (from p in dsProdutos.Tables[0].AsEnumerable()
                                     where !string.IsNullOrWhiteSpace(p.Field<string>("Codigo Hyperion")) && string.IsNullOrWhiteSpace(p.Field<string>("Descrição Hyperion"))
                                     select p).ToList();

                if (ProdutoGlobal != null && ProdutoGlobal.Count() > 0)
                    throw new Exception("Existem nomes de produtos globais em branco.\nPor favor, reveja a planilha e reinicie a importação.");

                var ProdutoFamilia = (from p in dsProdutos.Tables[0].AsEnumerable()
                                      where !string.IsNullOrWhiteSpace(p.Field<string>("Codigo Protheus")) && string.IsNullOrWhiteSpace(p.Field<string>("Descrição Protheus"))
                                      select p).ToList();

                if (ProdutoFamilia != null && ProdutoFamilia.Count() > 0)
                    throw new Exception("Existem nomes de produtos nacionais em branco.\nPor favor, reveja a planilha e reinicie a importação.");
            }
        }

        private void AtualizaUnidadeNegocio()
        {
            UnidadeNegocio Unidade = new UnidadeNegocio();
            OnImportData(this, new ImportDataEventArgs("Importando informações de BU..."));

            // Coluna H
            List<UnidadeNegocio.Itens> ProdutosExcel = (from p in dsProdutos.Tables[0].AsEnumerable()
                                                        where !string.IsNullOrWhiteSpace(p.Field<string>("BU"))
                                                        group p by p.Field<string>("BU").Trim() into g
                                                        select new UnidadeNegocio.Itens
                                                        {
                                                            NomeUnidadeNegocio = g.Key
                                                        }).ToList();

            List<UnidadeNegocio.Itens> ProdutosSQL = (from p in Unidade.GetAll()
                                                      select new UnidadeNegocio.Itens
                                                      {
                                                          NomeUnidadeNegocio = p.NOME_UNIDADE_NEGOCIO,
                                                          IdUnidadeNegocio = p.ID_UNIDADE_NEGOCIO
                                                      }).ToList();

            // Compara os arquivos do Excel com os existentes no Banco de Dados
            var Novos = (from p in ProdutosExcel
                         join db in ProdutosSQL
                         on p.NomeUnidadeNegocio equals db.NomeUnidadeNegocio
                         into produtos
                         from db in produtos.DefaultIfEmpty()
                         where db == null
                         select new UnidadeNegocio.Itens
                         {
                             NomeUnidadeNegocio = p.NomeUnidadeNegocio
                         }).ToList();

            int i = 0;
            if (Novos != null && Novos.Count() > 0)
            {
                foreach (var item in Novos)
                {
                    Unidade.Add(new TB_UNIDADE_NEGOCIO() { NOME_UNIDADE_NEGOCIO = item.NomeUnidadeNegocio, INDICA_ATIVO = true });
                    i++;
                    OnImportData(this, new ImportDataEventArgs("Incluindo BU...", i, Novos.Count()));
                }
            }

            if (Novos != null && Novos.Count() == 0)
                OnImportData(this, new ImportDataEventArgs("Os BU's já estão importados. Não foram realizadas importações."));
            else
                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
        }

        private void AtualizaProdutoTipo()
        {
            ProdutoTipo Tipo = new ProdutoTipo();
            OnImportData(this, new ImportDataEventArgs("Importando informações de Tipo de Produto..."));

            // Coluna I
            List<ProdutoTipo.Itens> ProdutosExcel = (from p in dsProdutos.Tables[0].AsEnumerable()
                                                     group p by p.Field<string>("Tipo").Trim() into g
                                                     select new ProdutoTipo.Itens
                                                     {
                                                         NomeProdutoTipo = g.Key
                                                     }).ToList();

            List<ProdutoTipo.Itens> ProdutosSQL = (from p in Tipo.GetItens()
                                                   select new ProdutoTipo.Itens
                                                   {
                                                       NomeProdutoTipo = p.NomeProdutoTipo
                                                   }).ToList();

            // Compara os arquivos do Excel com os existentes no Banco de Dados
            var Novos = (from p in ProdutosExcel
                         join db in ProdutosSQL
                         on p.NomeProdutoTipo equals db.NomeProdutoTipo
                         into produtos
                         from db in produtos.DefaultIfEmpty()
                         where db == null
                         select new ProdutoTipo.Itens
                         {
                             NomeProdutoTipo = p.NomeProdutoTipo
                         }).ToList();

            int i = 0;
            if (Novos != null && Novos.Count() > 0)
            {
                foreach (var item in Novos)
                {
                    Tipo.Add(new TB_PRODUTO_TIPO() { NOME_PRODUTO_TIPO = item.NomeProdutoTipo });
                    i++;
                    OnImportData(this, new ImportDataEventArgs("Incluindo Tipo de Produto...", i, Novos.Count()));
                }
            }

            if (Novos != null && Novos.Count() == 0)
                OnImportData(this, new ImportDataEventArgs("Os Tipos de Produtos já estão importados. Não foram realizadas importações."));
            else
                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
        }

        private void AtualizaProdutoFamilia()
        {
            ProdutoFamilia Familia = new ProdutoFamilia();
            OnImportData(this, new ImportDataEventArgs("Importando informações de Família de Produto Global..."));

            // Coluna F
            List<ProdutoFamilia.Itens> ProdutosExcel = (from p in dsProdutos.Tables[0].AsEnumerable()
                                                        where !string.IsNullOrWhiteSpace(p.Field<string>("Familia Hyperion"))
                                                        group p by p.Field<string>("Familia Hyperion").Trim() into g
                                                        select new ProdutoFamilia.Itens
                                                        {
                                                            NomeProdutoFamilia = g.Key
                                                        }).ToList();

            List<ProdutoFamilia.Itens> ProdutosSQL = (from p in Familia.GetAll()
                                                      select new ProdutoFamilia.Itens
                                                      {
                                                          NomeProdutoFamilia = p.NOME_PRODUTO_FAMILIA,
                                                          IdProdutoFamilia = p.ID_PRODUTO_FAMILIA
                                                      }).ToList();

            // Compara os arquivos do Excel com os existentes no Banco de Dados
            var Novos = (from p in ProdutosExcel
                         join db in ProdutosSQL
                         on p.NomeProdutoFamilia equals db.NomeProdutoFamilia
                         into produtos
                         from db in produtos.DefaultIfEmpty()
                         where db == null
                         select new ProdutoFamilia.Itens
                         {
                             NomeProdutoFamilia = p.NomeProdutoFamilia
                         }).ToList();

            int i = 0;
            if (Novos != null && Novos.Count() > 0)
            {
                foreach (var item in Novos)
                {
                    Familia.Add(new TB_PRODUTO_FAMILIA() { NOME_PRODUTO_FAMILIA = item.NomeProdutoFamilia, INDICA_ATIVO = true, INDICA_RECEBE_TRADE_ALLOWANCES = true });
                    i++;
                    OnImportData(this, new ImportDataEventArgs("Incluindo Família de Produto Global...", i, Novos.Count()));
                }
            }

            if (Novos != null && Novos.Count() == 0)
                OnImportData(this, new ImportDataEventArgs("As Famílias de Produtos Globais já estão importadas. Não foram realizadas importações."));
            else
                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
        }

        private void AtualizaProdutoGlobal()
        {
            ProdutoGlobal Global = new ProdutoGlobal();
            OnImportData(this, new ImportDataEventArgs("Importando informações de Produto Global..."));

            // Colunas A, D
            var ProdutosExcel = (from p in dsProdutos.Tables[0].AsEnumerable()
                                 where p.Field<object>("Codigo Hyperion") != null && !string.IsNullOrWhiteSpace(p.Field<string>("Codigo Hyperion"))
                                 select new ProdutoGlobal.Lista
                                 {
                                     CodigoProdutoGlobal = p.Field<string>("Codigo Hyperion").Trim().PadLeft(6, '0'),
                                     NomeProdutoGlobal = p.Field<string>("Descrição Hyperion").Trim()
                                 }).GroupBy(x => new { x.CodigoProdutoGlobal, x.NomeProdutoGlobal }).ToList();

            var ProdutosSQL = (from p in Global.GetLista()
                               select new ProdutoGlobal.Lista
                               {
                                   CodigoProdutoGlobal = p.CodigoProdutoGlobal,
                                   NomeProdutoGlobal = p.NomeProdutoGlobal,
                                   IdProdutoGlobal = p.IdProdutoGlobal,
                                   OrdemExibicao = p.OrdemExibicao
                               }).ToList();

            // Compara os arquivos do Excel com os existentes no Banco de Dados
            var Novos = (from p in ProdutosExcel
                         join db in ProdutosSQL
                         on p.Key.CodigoProdutoGlobal equals db.CodigoProdutoGlobal
                         into produtos
                         from db in produtos.DefaultIfEmpty()
                         where db == null && (p.Key.CodigoProdutoGlobal != null && p.Key.NomeProdutoGlobal != null)
                         select new ProdutoGlobal.Lista
                         {
                             CodigoProdutoGlobal = p.Key.CodigoProdutoGlobal,
                             NomeProdutoGlobal = p.Key.NomeProdutoGlobal
                         }).ToList();

            int i = 0;
            if (Novos != null && Novos.Count() > 0)
            {
                foreach (var item in Novos)
                {
                    Global.Add(new TB_PRODUTO_GLOBAL() { CODIGO_PRODUTO_GLOBAL = item.CodigoProdutoGlobal, NOME_PRODUTO_GLOBAL = item.NomeProdutoGlobal, INDICA_ATIVO = true });
                    i++;
                    OnImportData(this, new ImportDataEventArgs("Incluindo Produto Global...", i, Novos.Count()));
                }
            }

            var Alterados = (from p in ProdutosExcel
                             join db in ProdutosSQL
                             on p.Key.CodigoProdutoGlobal equals db.CodigoProdutoGlobal
                             where p.Key.NomeProdutoGlobal != db.NomeProdutoGlobal
                             select new ProdutoGlobal.Lista
                             {
                                 IdProdutoGlobal = db.IdProdutoGlobal,
                                 CodigoProdutoGlobal = p.Key.CodigoProdutoGlobal,
                                 NomeProdutoGlobal = p.Key.NomeProdutoGlobal,
                                 OrdemExibicao = db.OrdemExibicao
                             }).ToList();
            i = 0;
            if (Alterados != null && Alterados.Count() > 0)
            {
                foreach (var item in Alterados)
                {
                    Global.Update(new TB_PRODUTO_GLOBAL()
                    {
                        ID_PRODUTO_GLOBAL = item.IdProdutoGlobal,
                        CODIGO_PRODUTO_GLOBAL = item.CodigoProdutoGlobal,
                        NOME_PRODUTO_GLOBAL = item.NomeProdutoGlobal,
                        ORDEM_EXIBICAO = item.OrdemExibicao,
                        INDICA_ATIVO = true
                    });
                    i++;
                    OnImportData(this, new ImportDataEventArgs("Alterando Produto Global...", i, Alterados.Count()));
                }
            }

            if (Novos != null && Novos.Count() == 0 && Alterados != null && Alterados.Count() == 0)
                OnImportData(this, new ImportDataEventArgs("Os Produtos Globais já estão importados. Não foram realizadas importações."));
            else
                OnImportData(this, new ImportDataEventArgs("Importação efetuada com sucesso."));
        }

        private void AtualizaRelacaoProdutoNacionalGlobal()
        {
            Produto Produto = new Produto();
            var ProdutoSQL = Produto.GetLista();

            ProdutoGlobal Global = new ProdutoGlobal();
            var ProdutoGlobal = Global.GetItens().ToDictionary(d => d.CodigoProdutoGlobal);

            ProdutoTipo Tipo = new ProdutoTipo();
            var ProdutoTipo = Tipo.GetItens().ToDictionary(d => d.NomeProdutoTipo);

            UnidadeNegocio Unidade = new UnidadeNegocio();
            var UnidadeNegocio = Unidade.GetItens().ToDictionary(d => d.NomeUnidadeNegocio);

            ProdutoFamilia Familia = new ProdutoFamilia();
            var ProdutoFamilia = Familia.GetItens().ToDictionary(d => d.NomeProdutoFamilia);

            CentroCusto CentroCusto = new CentroCusto();
            var CentrosCustos = CentroCusto.GetLista(new CentroCusto.Lista() { IndicaGerencial = false })
                .GroupBy(g => g.CodigoCentroCusto.PadLeft(8,'0')
                    ).Select(sl => new CentroCusto.Lista(){
                        IdCentroCusto = sl.First().IdCentroCusto,
                        CodigoCentroCusto = sl.Key }).ToDictionary(d => d.CodigoCentroCusto);

            var Produtos = from p in dsProdutos.Tables[0].AsEnumerable()
                           where p.Field<object>("Codigo Protheus") != null && !string.IsNullOrWhiteSpace(p.Field<string>("Codigo Protheus"))
                           join db in ProdutoSQL
                           on p.Field<string>("Codigo Protheus").Trim().PadLeft(9, '0') equals db.CodigoProduto
                           select new TB_PRODUTO
                           {
                               ID_PRODUTO = db.IdProduto,
                               CODIGO_PRODUTO = db.CodigoProduto,
                               NOME_PRODUTO = db.NomeProduto,
                               ID_CENTRO_CUSTO = string.IsNullOrWhiteSpace(p.Field<string>("Centro de Custos")) ? null : CentrosCustos.ContainsKey(p.Field<string>("Centro de Custos").Substring(0, 8)) == true ? (int?)CentrosCustos[p.Field<string>("Centro de Custos").Substring(0, 8)].IdCentroCusto : null,
                               ID_PRODUTO_PAI = db.IdProdutoPai,
                               INDICA_ATIVO = db.IndicaAtivo,
                               CODIGO_PRODUTO_SEMI_ACABADO = db.CodigoProdutoSemiAcabado,
                               ID_PRODUTO_GLOBAL = string.IsNullOrWhiteSpace(p.Field<string>("Codigo Hyperion")) ? null : (int?)ProdutoGlobal[p.Field<string>("Codigo Hyperion").Trim()].IdProdutoGlobal,
                               ID_PRODUTO_TIPO = string.IsNullOrWhiteSpace(p.Field<string>("Tipo")) ? null : (int?)ProdutoTipo[p.Field<string>("Tipo").Trim()].IdProdutoTipo,
                               ID_UNIDADE_NEGOCIO = string.IsNullOrWhiteSpace(p.Field<string>("BU")) ? null : (int?)UnidadeNegocio[p.Field<string>("BU").Trim()].IdUnidadeNegocio,
                               ID_PRODUTO_FAMILIA = string.IsNullOrWhiteSpace(p.Field<string>("Familia Hyperion")) ? null : (int?)ProdutoFamilia[p.Field<string>("Familia Hyperion").Trim()].IdProdutoFamilia
                           };

            int i = 0;
            foreach (var item in Produtos)
            {
                this.Update(item);
                i++;
                OnImportData(this, new ImportDataEventArgs("Atualizando relacionamentos dos produtos...", i, Produtos.Count()));
            }

            OnImportData(this, new ImportDataEventArgs("Relacionamentos atualizados com sucesso."));
        }


        private void EXEMPLO()
        {
            Produto Produto = new Produto();
            var ProdutoSQL = Produto.GetLista();

            ProdutoGlobal Global = new ProdutoGlobal();
            var ProdutoGlobal = Global.GetItens();

            ProdutoTipo Tipo = new ProdutoTipo();
            var ProdutoTipo = Tipo.GetItens();

            UnidadeNegocio Unidade = new UnidadeNegocio();
            var UnidadeNegocio = Unidade.GetItens();

            ProdutoFamilia Familia = new ProdutoFamilia();
            var ProdutoFamilia = Familia.GetItens();

            CentroCusto CentroCusto = new CentroCusto();
            var CentrosCustos = CentroCusto.GetLista(new CentroCusto.Lista() { IndicaGerencial = false });

            var Produtos = from p in dsProdutos.Tables[0].AsEnumerable()
                           where p.Field<object>("Codigo Protheus") != null && !string.IsNullOrWhiteSpace(p.Field<string>("Codigo Protheus"))
                           join db in ProdutoSQL
                           on p.Field<string>("Codigo Protheus").Trim().PadLeft(9, '0') equals db.CodigoProduto
                           join g in ProdutoGlobal
                           on p.Field<string>("Codigo Hyperion") equals g.CodigoProdutoGlobal
                           join tp in ProdutoTipo
                           on p.Field<string>("Tipo") equals tp.NomeProdutoTipo
                           join un in UnidadeNegocio
                           on p.Field<string>("BU") equals un.NomeUnidadeNegocio
                           join fm in ProdutoFamilia
                           on p.Field<string>("Familia Hyperion") equals fm.NomeProdutoFamilia
                           join c in CentrosCustos
                           on p.Field<string>("Centro de Custos").PadLeft(8) equals c.CodigoCentroCusto.PadLeft(8, '0')
                           into jn
                           from c in jn.DefaultIfEmpty()
                           select new TB_PRODUTO
                           {
                               ID_PRODUTO = db.IdProduto,
                               CODIGO_PRODUTO = db.CodigoProduto,
                               NOME_PRODUTO = db.NomeProduto,
                               ID_CENTRO_CUSTO = c == null ? (int?)null : c.IdCentroCusto,
                               ID_PRODUTO_PAI = db.IdProdutoPai,
                               INDICA_ATIVO = db.IndicaAtivo,
                               CODIGO_PRODUTO_SEMI_ACABADO = db.CodigoProdutoSemiAcabado,
                               ID_PRODUTO_GLOBAL = (int?)g.IdProdutoGlobal,
                               ID_PRODUTO_TIPO = (int?)tp.IdProdutoTipo,
                               ID_UNIDADE_NEGOCIO = (int?)un.IdUnidadeNegocio,
                               ID_PRODUTO_FAMILIA = (int?)fm.IdProdutoFamilia
                           };

            foreach (var item in Produtos)
            {
                this.Update(item);
            }
        }

        #endregion Importa Produtos Globais

        #region Sincroniza Produtos Nacionais

        public void SincronizarProdutosNacionais()
        {
            try
            {
                OnImportData(this, new ImportDataEventArgs("Acessando Banco de Dados Protheus..."));

                Protheus.BLL.SpProdutoGaldermaNacional ProcedureProdutos = new Protheus.BLL.SpProdutoGaldermaNacional();
                List<Itens> ProdutosProtheus = (from p in ProcedureProdutos.ExecutaProcedure()
                                                select new Itens
                                                {
                                                    NomeProduto = p.NomeProduto,
                                                    CodigoProduto = p.CodigoProduto
                                                }).ToList();

                OnImportData(this, new ImportDataEventArgs("Acessando informações de Produtos..."));

                List<Itens> ProdutosSQL = (from p in Get(new Lista())
                                           select new Itens
                                           {
                                               CodigoProduto = p.CODIGO_PRODUTO,
                                               NomeProduto = p.NOME_PRODUTO,
                                               IdProduto = p.ID_PRODUTO
                                           }).ToList();

                var Novos = (from pr in ProdutosProtheus
                             join db in ProdutosSQL
                             on pr.CodigoProduto equals db.CodigoProduto
                             into produtos
                             from db in produtos.DefaultIfEmpty()
                             where db == null
                             select new Itens
                             {
                                 CodigoProduto = pr.CodigoProduto,
                                 NomeProduto = pr.NomeProduto
                             }).ToList();

                int i = 0;
                if (Novos != null && Novos.Count() > 0)
                {
                    foreach (var item in Novos)
                    {
                        this.Add(new TB_PRODUTO() { CODIGO_PRODUTO = item.CodigoProduto, NOME_PRODUTO = item.NomeProduto });
                        i++;
                        OnImportData(this, new ImportDataEventArgs("Incluindo Produtos...", i, Novos.Count()));
                    }
                }

                List<Itens> Alterados = (from pr in ProdutosProtheus
                                         join db in ProdutosSQL
                                         on pr.CodigoProduto equals db.CodigoProduto
                                         where pr.NomeProduto != db.NomeProduto
                                         select new Itens
                                         {
                                             IdProduto = db.IdProduto,
                                             CodigoProduto = pr.CodigoProduto,
                                             NomeProduto = pr.NomeProduto
                                         }).ToList();
                i = 0;
                if (Alterados != null && Alterados.Count() > 0)
                {
                    foreach (var item in Alterados)
                    {
                        this.Update(new TB_PRODUTO() { ID_PRODUTO = item.IdProduto, CODIGO_PRODUTO = item.CodigoProduto, NOME_PRODUTO = item.NomeProduto });
                        i++;
                        OnImportData(this, new ImportDataEventArgs("Alterando Produtos...", i, Alterados.Count()));
                    }
                }

                if (Novos != null && Novos.Count() == 0 && Alterados != null && Alterados.Count() == 0)
                    OnImportData(this, new ImportDataEventArgs("Os Produtos já estão sincronizados. Não foram realizadas alterações."));
                else
                    OnImportData(this, new ImportDataEventArgs("Sincronização efetuada com sucesso."));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        #endregion Sincroniza Produtos Nacionais

        #endregion Processos

        #region Métodos

        public static void GetDrivers(Lista pProduto, int pIdPeriodo)
        {
            if (pIdPeriodo > 0)
            {
                ProdutoDriverRateioValor pdrv = new ProdutoDriverRateioValor();
                Lista ValoresDriver = (from s in pdrv.GetLista(new ProdutoDriverRateioValor.Lista() { IdPeriodo = pIdPeriodo, IdProduto = pProduto.IdProduto })
                                       select new Lista
                                        {
                                            DriverGGF = s.ValorGGF,
                                            DriverNetNet = s.ValorNetNet,
                                            DriverVenda = s.ValorVenda
                                        }).FirstOrDefault();

                if (ValoresDriver != null)
                {
                    pProduto.DriverGGF = ValoresDriver.DriverGGF;
                    pProduto.DriverNetNet = ValoresDriver.DriverNetNet;
                    pProduto.DriverVenda = ValoresDriver.DriverVenda;
                }


                if (pProduto.IdProdutoFamilia != null)
                {
                    ProdutoFamiliaDriverRateioValor pfdrv = new ProdutoFamiliaDriverRateioValor();
                    ValoresDriver = (from s in pfdrv.GetLista(new ProdutoFamiliaDriverRateioValor.Lista() { IdPeriodo = pIdPeriodo, IdProdutoFamilia = (int)pProduto.IdProdutoFamilia })
                                     select new Lista
                                     {
                                         DriverGradePromocional = s.ValorPromocaoGrade
                                     }).FirstOrDefault();

                    if (ValoresDriver != null)
                    {
                        pProduto.DriverGradePromocional = ValoresDriver.DriverGradePromocional;
                    }
                }
            }
        }

        #endregion Métodos

        #region Classes

        /// <summary>
        /// Preenche o combobox
        /// </summary>
        public class Itens
        {
            public int IdProduto { get; set; }
            public string CodigoProduto { get; set; }
            public string NomeProduto { get; set; }
        }

        /// <summary>
        /// Lista com as propriedades da classe
        /// </summary>
        public class Lista
        {
            public int IdProduto { get; set; }
            public string CodigoProduto { get; set; }
            public string NomeProduto { get; set; }
            public bool? IndicaAtivo { get; set; }
            public int? IdProdutoGlobal { get; set; }
            public string CodigoProdutoGlobal { get; set; }
            public string NomeProdutoGlobal { get; set; }
            public int? IdProdutoPai { get; set; }
            public string NomeProdutoPai { get; set; }
            public int? IdCentroCusto { get; set; }
            public string NomeCentroCusto { get; set; }
            public string CodigoProdutoSemiAcabado { get; set; }
            public int? IdProdutoTipo { get; set; }
            public string NomeProdutoTipo { get; set; }
            public int? IdProdutoFamilia { get; set; }
            public string NomeProdutoFamilia { get; set; }
            public int? IdUnidadeNegocio { get; set; }
            public string NomeUnidadeNegocio { get; set; }
            public decimal? DriverGGF { get; set; }
            public decimal? DriverVenda { get; set; }
            public decimal? DriverNetNet { get; set; }
            public decimal? DriverGradePromocional { get; set; }
            public int? IdPeriodo { get; set; }
        }

        #endregion Classes

        public event ImportDataEventHandler OnImportData;
    }

    public class ProdutoBLO<T> : IBLO<T> where T : TB_PRODUTO
    {
        /// <summary>
        /// ProdutoDAO
        /// </summary>
        private ProdutoDAO<T> _base = new ProdutoDAO<T>();

        /// <summary>
        /// Adiciona uma entidade no sistema
        /// </summary>
        /// <param name="pEntity">pEntity</param>
        /// <returns>Entidade</returns>
        public T Add(T pEntity)
        {
            Validate(pEntity);
            _base.Add(pEntity);
            return _base.Save(pEntity);
        }

        /// <summary>
        /// Salva uma entidade do sistema
        /// </summary>
        /// <param name="pEntity">pEntity</param>
        /// <returns>Entidade</returns>
        public T Save(T pEntity)
        {
            Validate(pEntity);
            return _base.Save(pEntity);
        }

        /// <summary>
        /// Deleta uma entidade do sistema
        /// </summary>
        /// <param name="pEntity">pEntity</param>
        public void Delete(T pEntity)
        {
            _base.Delete(pEntity);
            _base.Save(pEntity);
        }

        /// <summary>
        /// Atualiza uma entidade do sistema
        /// </summary>
        /// <param name="pEntity">pEntity</param>
        /// <returns>Entidade</returns>
        public T Update(T pEntity)
        {
            Validate(pEntity);
            _base.Update(pEntity);
            return _base.Save(pEntity);
        }

        /// <summary>
        /// Recupera uma entidade do sistema
        /// </summary>
        /// <returns>Lista</returns>
        public IQueryable<T> GetAll()
        {
            return _base.GetAll();
        }

        /// <summary>
        /// Valida a consistência da Entidade antes de 'comitar' a transação
        /// </summary>
        /// <param name="pEntity">Entidade</param>
        public void Validate(T pEntity)
        {
            int validate = (from u in _base.GetAll()
                            where (u.CODIGO_PRODUTO == pEntity.CODIGO_PRODUTO && u.ID_PRODUTO != pEntity.ID_PRODUTO)
                            select u).Count();

            if (validate > 0)
                throw new Exception("Já existe um produto cadastrado com esse código.");

            //validate = (from u in _base.GetAll()
            //            where (u.ID_PRODUTO_GLOBAL == pEntity.ID_PRODUTO_GLOBAL && u.ID_PRODUTO != pEntity.ID_PRODUTO)
            //            select u).Count();

            //if (validate > 0)
            //    throw new Exception("Já existe um produto relacionado com esse produto.");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pEntity"></param>
        public void ValidateDelete(T pEntity)
        {
            //int Perfilvalidate = (from u in _base.GetAll()
            //                      where u..Where(w => w.ID_PERFIL_ACESSO == pEntity.ID_PERFIL_ACESSO).Select(s => s).Count() > 0
            //                      select u).Count();

            //if (Perfilvalidate > 0)
            //    throw new Exception("Existem usuários relacionados com este perfil de acesso.\nA operação não pôde ser concluída");
        }
    }
}